package org.budo.criteria.parser;

import java.util.Collection;
import java.util.List;

import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.spring.context.aware.BudoApplicationContextAware;
import org.springframework.context.ApplicationContext;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Getter
@Setter
@Slf4j
public class MybatisCriteriaParser extends BudoCriteriaParser {
    @Override
    protected String fieldName(Class<?> type, String field) {
        if (null == type) {
            return field;
        }

        BudoApplicationContextAware applicationContextAware = BudoApplicationContextAware.getInstanceNoNull();
        ApplicationContext applicationContext = applicationContextAware.getApplicationContext();
        String[] beanNames = applicationContext.getBeanNamesForType(SqlSessionFactory.class);
        for (String beanName : beanNames) {
            String column = this.fieldToColumn(type, field, applicationContext, beanName);
            if (StringUtil.isNotNullOrEmpty(column)) {
                return column;
            }
        }

        return super.fieldName(type, field);
    }

    private String fieldToColumn(Class<?> type, String field, ApplicationContext applicationContext, String beanName) {
        if (null == type) {
            return field;
        }

        SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) applicationContext.getBean(beanName);
        Configuration configuration = sqlSessionFactory.getConfiguration();
        Collection<?> resultMaps = configuration.getResultMaps();
        for (Object each : resultMaps) {
            if (!(each instanceof ResultMap)) {
                log.info("#46 fieldToColumn continue, type=" + each.getClass().getName() + ", field=" + field + ", beanName=" + beanName + ", resultMap=" + each);
                continue;
            }

            ResultMap resultMap = (ResultMap) each;
            Class<?> resultMapType = resultMap.getType();

            if (resultMapType.isAssignableFrom(type)) {
                List<ResultMapping> resultMappings = resultMap.getResultMappings();
                for (ResultMapping resultMapping : resultMappings) {
                    if (field.equals(resultMapping.getProperty())) {
                        return resultMapping.getColumn();
                    }
                }
            }
        }

        return null;
    }
}